package com.tuanzi.loan.web.configuration;

import java.util.Iterator;

import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.application.ProjectStage;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;

import org.hibernate.StaleObjectStateException;
import org.springframework.retry.RetryException;

import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.core.exception.ValidateException;
import com.tuanzi.loan.security.AuthenticationFailureType;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Ray 2017/09/21
 */
@Slf4j
public class JSFExceptionHandler extends ExceptionHandlerWrapper {
	private final ExceptionHandler wrapped;

	private static final String PRODUCTION_MESSAGE = "系统错误,请联系系统管理员";

	public JSFExceptionHandler(final ExceptionHandler wrapped) {
		this.wrapped = wrapped;
	}

	@Override
	public ExceptionHandler getWrapped() {
		return this.wrapped;
	}

	@Override
	public void handle() throws FacesException {
		for (final Iterator<ExceptionQueuedEvent> it = getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();) {

			Throwable t = it.next().getContext().getException();

			while (t.getCause() != null) {
				t = t.getCause();
			}

			try {
				if (t instanceof ViewExpiredException) {
					FacesContext.getCurrentInstance().getExternalContext().redirect(FacesContext.getCurrentInstance().getExternalContext().getApplicationContextPath()
							+ "/login.xhtml?failureType=" + AuthenticationFailureType.SESSION_TIMEOUT);

				} else if (t instanceof ValidateException || t instanceof SystemException || t instanceof RetryException) {

					addMessage(t.getMessage());

				} else if (t instanceof StaleObjectStateException) {

					addMessage("您所在的页面已经过期, 请重新刷新页面");

				} else {

					log.error(t.getMessage(), t);
					if (FacesContext.getCurrentInstance().getApplication().getProjectStage() == ProjectStage.Production) {
						addMessage(PRODUCTION_MESSAGE);
					} else {
						addMessage("后台错误: " + t.getMessage());
					}

				}
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				throw new SystemException(e);
			} finally {
				it.remove();
			}
		}
		getWrapped().handle();
	}

	private void addMessage(String message) {
		FacesMessage facesMessage = new FacesMessage();
		facesMessage.setSummary(message);
		facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
		FacesContext.getCurrentInstance().addMessage(null, facesMessage);
	}

}
